1 module hip.game2d.threepatch;
2 
3 public import hip.api.renderer.texture;
4 public import hip.game2d.sprite;
5 import hip.api.renderer.shaders.spritebatch;
6 import hip.api.data.textureatlas;
7 
8 enum ThreePatchOrientation
9 {
10     horizontal,
11     vertical,
12     inferred
13 }
14 
15 
16 final class ThreePatch
17 {
18     int x, y;
19     int width, height;
20     HipSpriteVertex[4*3] vertices;
21     HipSprite[3] sprites;
22     protected ThreePatchOrientation orientation = ThreePatchOrientation.inferred;
23 
24     protected this(IHipTexture tex, ThreePatchOrientation o)
25     {
26         foreach(i; 0..3)
27         {
28             sprites[i] = new HipSprite(tex);
29             sprites[i].setOrigin(0,0);
30         }
31         this.orientation = o == ThreePatchOrientation.inferred ? infer(tex) : o;
32     }
33 
34     pragma(inline) ThreePatchOrientation getOrientation()
35     {
36         return orientation;
37     }
38     void setOrientation(ThreePatchOrientation ori = ThreePatchOrientation.horizontal)
39     {
40         if(ori == ThreePatchOrientation.inferred)
41             ori = infer(this.sprites[0].getTexture);
42         if(ori != orientation)
43         {
44             orientation = ori;
45             build();
46         }
47     }
48 
49     /**
50      *
51      * Params:
52      *   rects = The regions that is used as reference for this three patch
53      *   tex = Texture reference for the regions
54      *   width = Width of the resulting threepatch
55      *   height = Height of the resulting threepatch
56      *   o = Orientation of the threepatch, default is inferred.
57      * Returns:
58      */
59     static ThreePatch fromQuads(AtlasRect[3] rects, IHipTexture tex, int width, int height,  ThreePatchOrientation o = ThreePatchOrientation.inferred)
60     {
61         ThreePatch t = new ThreePatch(tex, o);
62         AtlasSize sz = AtlasSize(tex.getWidth, tex.getHeight);
63         foreach(i; 0..3)
64             t.sprites[i].setRegion(rects[i].toQuad(sz));
65         t.setSize(width, height);
66         return t;
67     }
68 
69     /**
70      *
71      * Params:
72      *   tex = Takes a texture, divide it into 3 [depending on orientation], and assemble the threepatch
73      *   width = Width of the resulting texture
74      *   height = Height of the resulting texture
75      *   o = Orientation of the threepatch, default is inferred.
76      * Returns:
77      */
78     static ThreePatch fromTexture(IHipTexture tex, int width, int height, ThreePatchOrientation o = ThreePatchOrientation.inferred)
79     {
80         ThreePatch ret = new ThreePatch(tex, o);
81 
82         int w = tex.getWidth;
83         int h = tex.getHeight;
84 
85         if(o == ThreePatchOrientation.inferred)
86             o = w >= h ? ThreePatchOrientation.horizontal : ThreePatchOrientation.vertical;
87 
88         if(o == ThreePatchOrientation.horizontal)
89         {
90             float rw = cast(float)w/3;
91             ret.sprites[0].setRegion(0, 0, rw, 1.0);
92             ret.sprites[1].setRegion(rw, 0, rw*2, 1.0);
93             ret.sprites[2].setRegion(rw*2, 0, rw*3, 1.0);
94         }
95         else
96         {
97             float rh = cast(float)h/3;
98             ret.sprites[0].setRegion(0, 0, rh, 1.0);
99             ret.sprites[1].setRegion(rh, 0, rh*2, 1.0);
100             ret.sprites[2].setRegion(rh*2, 0, rh*3, 1.0);
101         }
102         ret.setSize(width, height);
103         return ret;
104     }
105 
106     void setSize(int width, int height)
107     {
108         this.width = width;
109         this.height = height;
110         build();
111     }
112 
113     protected void updatePosition()
114     {
115         if(getOrientation == ThreePatchOrientation.horizontal)
116         {
117             sprites[0].setPosition(x, y);
118             sprites[1].setPosition(x+sprites[0].width, y);
119             sprites[2].setPosition(x+width - (sprites[2].width),  y);
120         }
121         else
122         {
123             sprites[0].setPosition(x, y);
124             sprites[1].setPosition(x, y + sprites[0].getHeight);
125             sprites[2].setPosition(x, y + height - sprites[2].height);
126         }
127     }
128 
129     void build()
130     {
131         import hip.api;
132         updatePosition();
133         if(getOrientation == ThreePatchOrientation.horizontal)
134         {
135             int spWidth = sprites[0].getWidth+sprites[2].getWidth;
136             float xScalingFactor = cast(float)(width - spWidth) / sprites[1].getWidth;
137             sprites[1].setScale(xScalingFactor, 1);
138         }
139         else
140         {
141             int spHeight = sprites[0].getHeight+sprites[2].getHeight;
142             float yScalingFactor = cast(float)(height - spHeight) / sprites[1].getHeight;
143 
144             sprites[1].setScale(1, yScalingFactor);
145         }
146 
147 
148     }
149 
150     void draw()
151     {
152         import hip.api;
153         foreach(sp; sprites)
154             sp.draw;
155     }
156 
157     
158 
159     void setPosition(int x, int y)
160     {
161         this.x = x;
162         this.y = y;
163         updatePosition();
164     }
165 
166     ref HipSpriteVertex[4*3] getVertices(){return vertices;}
167 
168 }
169 
170 private ThreePatchOrientation infer(int width, int height){return width > height ? ThreePatchOrientation.horizontal : ThreePatchOrientation.vertical;}
171 private ThreePatchOrientation infer(const IHipTexture tex){return tex.getWidth > tex.getHeight ? ThreePatchOrientation.horizontal : ThreePatchOrientation.vertical;}
172 
173 
174 /**
175 *     0  1  2 
176 *    ________
177 *   |________|
178 *
179 *
180 *    ___
181 *   |   | 0
182 *   |   | 1
183 *   |___| 2
184 */